<?php


namespace EchoPHP\Database\TuxedoDriver;

use InvalidArgumentException;

class TuxedoMultiTransactionStatement extends TransactionHandler {

    protected $tuxedoTransactionStatements = [];

    public function __construct($tuxedoTransactionStatements) {
        parent::__construct();

        $this->prepareStatements($tuxedoTransactionStatements);
    }

    /**
     * 执行事务
     * @return mixed
     */
    public function execute() {
        $oracleDbCount = isset($this->tuxedoTransactionStatements['ORACLE']) ? count($this->tuxedoTransactionStatements['ORACLE']) : 0;
        $mysqlDbCount = isset($this->tuxedoTransactionStatements['MYSQL']) ? count($this->tuxedoTransactionStatements['MYSQL']) : 0;

        if ($oracleDbCount + $mysqlDbCount <= 1) {
            throw new InvalidArgumentException('跨库事务至少需要涉及2个数据库');
        }
        if ($oracleDbCount > 1) {
            throw new InvalidArgumentException('跨库事务暂不支持多ORACLE数据库操作');
        }
        $serverName = 'FULL_BAT';
        $this->setServerName($serverName);

        $sendBufferParams = [
            $mysqlDbCount
        ];
        $this->setSendBuffer('');
        $this->pushSendBuffer($sendBufferParams);
        $querySqls = [];
        foreach ($this->tuxedoTransactionStatements['MYSQL'] as $dbId => $item) {
            $rollBackNoAffects = $item['rollbackIfNoAffects'];
            $statements = $item['statements'];

            $sendBufferParams = [
                $rollBackNoAffects, $dbId, count($statements)
            ];
            $this->pushSendBuffer($sendBufferParams);
            foreach ($statements as $statement) {
                /* @var TuxedoStatement $statement */
                $this->pushSendBuffer($statement->mergeSendBuffer(true));
                $querySqls[] = [
                    'serverdbtype' => $statement->getDbType(),
                    'dbid' => $statement->getDbId(),
                    'query' => $statement->getSql(),
                    'bindings' => $statement->getVar(),
                ];
            }
        }
        if ($oracleDbCount == 0) {
            $sendBufferParams = [
                1, 1, 0
            ];
            $this->pushSendBuffer($sendBufferParams);
        } else {
            foreach ($this->tuxedoTransactionStatements['ORACLE'] as $dbId => $item) {
                $rollBackNoAffects = $item['rollbackIfNoAffects'];
                $statements = $item['statements'];

                $sendBufferParams = [
                    $rollBackNoAffects, $dbId, count($statements)
                ];
                $this->pushSendBuffer($sendBufferParams);
                foreach ($statements as $statement) {
                    /* @var TuxedoStatement $statement */
                    $this->pushSendBuffer($statement->mergeSendBuffer(true));
                    $querySqls[] = [
                        'serverdbtype' => $statement->getDbType(),
                        'dbid' => $statement->getDbId(),
                        'query' => $statement->getSql(),
                        'bindings' => $statement->getVar(),
                    ];
                }
            }
        }

        return $this->run($querySqls);
    }

    /**
     * 整理语句
     * @param $tuxedoTransactionStatements
     */
    protected function prepareStatements($tuxedoTransactionStatements) {
        $this->tuxedoTransactionStatements = [];
        foreach ($tuxedoTransactionStatements as $statement) {
            if (!($statement instanceof TuxedoTransactionStatement)) {
                throw new InvalidArgumentException('跨库事务需要传入[TuxedoTransactionStatement] 类型的参数');
            }
            /* @var $statement TuxedoTransactionStatement */
            $this->pushStatement($statement);
        }
    }

    /**
     * 在执行队列尾部加入一条执行语句
     * @param TuxedoTransactionStatement $tuxedoTransactionStatement
     */
    public function pushStatement(TuxedoTransactionStatement $tuxedoTransactionStatement) {
        $server = $tuxedoTransactionStatement->getServer();
        $dbId = $tuxedoTransactionStatement->getDbId();
        $rollbackIfNoAffects = $tuxedoTransactionStatement->getRollbackIfNoAffects();

        if (isset($this->tuxedoTransactionStatements[$server][$dbId])) {
            $this->tuxedoTransactionStatements[$server][$dbId]['rollbackIfNoAffects'] = ($this->tuxedoTransactionStatements[$server][$dbId]['rollbackIfNoAffects'] && $rollbackIfNoAffects) ? 1 : 0;
            $this->tuxedoTransactionStatements[$server][$dbId]['statements'] = array_merge($this->tuxedoTransactionStatements[$server][$dbId]['statements'], $tuxedoTransactionStatement->getStatements());
        } else {
            $this->tuxedoTransactionStatements[$server][$dbId]['rollbackIfNoAffects'] = $rollbackIfNoAffects;
            $this->tuxedoTransactionStatements[$server][$dbId]['statements'] = $tuxedoTransactionStatement->getStatements();
        }
    }

}